﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Concurrency;
using System.Diagnostics.Contracts;


namespace ReactiveCode.Util
{
    
    static class SchedulerUtil
    {
        class AnonumousScheduler: IScheduler
        {
            internal Func<DateTimeOffset> _now;
            public DateTimeOffset Now
            {
                get { return _now(); }
            }

            internal Func<Action, TimeSpan, IDisposable> _scheduleWithDueTime;
            public IDisposable Schedule(Action action, TimeSpan dueTime)
            {
                return _scheduleWithDueTime(action, dueTime);
            }

            internal Func<Action, IDisposable> _schedule;
            public IDisposable Schedule(Action action)
            {
                return _schedule(action);
            }

        }
        public static IScheduler Create(Func<Action, IDisposable> schedule, Func<Action, TimeSpan, IDisposable> scheduleWithDueTime, Func<DateTimeOffset> now)
        {
            Contract.Requires(schedule != null && now != null);
            return new AnonumousScheduler { _schedule = schedule, _scheduleWithDueTime = scheduleWithDueTime, _now = now };
        }
        public static IScheduler Select(this IScheduler scheduler, Func<Action, Action> actionSelector)
        {
            Contract.Requires(scheduler != null && actionSelector != null);
            return Create
            (
                schedule: action => 
                {
                    action = actionSelector(action);
                    if (action == null)
                        return Disposable.Empty;
                    return scheduler.Schedule(action);
                }, 
                scheduleWithDueTime: (action, dueTime) => 
                {
                    action = actionSelector(action);
                    if (action == null)
                        return Disposable.Empty;
                    return scheduler.Schedule(action, dueTime);
                }, 
                now:() => scheduler.Now
            );
        }
    }
}
